package rps.game;

import java.rmi.RemoteException;

import rps.game.data.Figure;
import rps.game.data.FigureKind;
import rps.game.data.Move;
import rps.game.data.Player;

public class ValidatingGame implements Game {

	/**
	 * game object
	 */
	private final Game game;
	
	/**
	 * player object
	 */
	private final Player player;
	
	public ValidatingGame(Game game, Player player) throws RemoteException {
		this.game = game;
		this.player = player;
	}

	@Override
	public void setInitialAssignment(Player p, FigureKind[] assignment) throws RemoteException {
		//wrong player -> manipulated!
		if (!p.equals(player)) {
			surrenderWithException(player);
			return;
		}
		
		//wrong assignment size -> manipulated!
		if (assignment.length != 42) {
			surrenderWithException(p);
			return;
		}
		
		//check the first 28 fields. they must be null otherwise -> manipulated!
		for (int i=0;i<28;i++) {
			if (assignment[i] != null) {
				surrenderWithException(p);
				return;
			}
		}

		//counter variables for each figurekind
		int rocks = 0;
		int papers = 0;
		int scissors = 0;
		int flags = 0;
		int traps = 0;
		
		//count the figurekinds
		for (int i=28;i<42;i++) {
			switch (assignment[i]) {
			case ROCK:
				rocks++;
				break;
			case PAPER:
				papers++;
				break;
			case SCISSORS:
				scissors++;
				break;
			case FLAG:
				flags++;
				break;
			case TRAP:
				traps++;
				break;
			case HIDDEN:
				surrenderWithException(p);
				return;
			default:
				break;
			}
		}
		
		//if number of pieces is wrong -> manipulated!
		if (rocks != 4 || papers != 4 || scissors != 4 || traps != 1 || flags != 1) {
			surrenderWithException(p);
			return;
		}
		
		//no error
		game.setInitialAssignment(p, assignment);
	}

	@Override
	public Figure[] getField() throws RemoteException {
		Figure[] figureSet = game.getField();
		
		//if length is wrong -> manipulated!
		if (figureSet.length != 42) {
			surrenderWithException(player);
		}
		
		return figureSet;
	}

	@Override
	public void move(Player p, int from, int to) throws RemoteException {
		//wrong player -> manipulated!
		if (!p.equals(player)) {
			surrenderWithException(player);
			return;
		}
		
		//out of bounds -> manipulated!
		if (from >= 42 || to >= 42) {
			surrenderWithException(p);
			return;
		}
		
		Figure[] figureSet = getField();
		
		//trying to move empty field -> manipulated!
		if (figureSet[from] == null) {
			surrenderWithException(p);
			return;
		}
		
		//figure belongs to wrong player -> manipulated!
		if (!figureSet[from].belongsTo(p)) {
			surrenderWithException(p);
			return;
		}
		
		//target belongs to same player -> manipulated!
		if (figureSet[to] != null) {
			if (figureSet[to].belongsTo(p)) {
				surrenderWithException(p);
				return;
			}
		}
		
		//move to wrong field -> manipulated!
		if (from+1 != to && from-1 != to && from+7 != to && from-7 != to) {
			surrenderWithException(p);
			return;
		}
		
		//move across field borders -> manipulated!
		if (from%7 == 0 && from-1 == to ||
				from%7 == 6 && from+1 == to) {
			surrenderWithException(p);
			return;
		}
		
		//trying to move immovable piece -> manipulated!
		if (figureSet[from].getKind() == FigureKind.TRAP ||
				figureSet[from].getKind() == FigureKind.FLAG ||
				figureSet[from].getKind() == FigureKind.HIDDEN) {
			surrenderWithException(p);
			return;
		}
		
		game.move(p, from, to);
	}

	@Override
	public Move getLastMove() throws RemoteException {
		Move move = game.getLastMove();
		Figure[] figureSet = move.getOldField();
		int from = move.getFrom();
		int to = move.getTo();
		
		//trying to move empty field -> manipulated!
		if (figureSet[move.getFrom()] == null) {
			surrenderWithException(player);
		}
		
		//moved figure belongs to player of target figure -> manipulated!
		if (figureSet[to] != null) {
			if (figureSet[from].belongsTo(player) && figureSet[to].belongsTo(player) ||
					!figureSet[from].belongsTo(player) && !figureSet[to].belongsTo(player)) {
				surrenderWithException(player);
			}
		}
		
		//move to wrong field -> manipulated!
		if (from+1 != to && from-1 != to && from+7 != to && from-7 != to) {
			surrenderWithException(player);
		}

		//move across field borders -> manipulated!
		if (from%7 == 0 && from-1 == to ||
				from%7 == 6 && from+1 == to) {
			surrenderWithException(player);
		}
		
		return game.getLastMove();
	}

	@Override
	public void sendMessage(Player p, String message) throws RemoteException {
		game.sendMessage(p, message);
	}

	@Override
	public void setInitialChoice(Player p, FigureKind kind) throws RemoteException {
		//wrong player -> manipulated!
		if (!p.equals(player)) {
			surrenderWithException(player);
			return;
		}
		
		//choice is no valid figure kind -> manipulated!
		switch (kind) {
		case FLAG:
			surrenderWithException(p);
			return;
		case HIDDEN:
			surrenderWithException(p);
			return;
		case TRAP:
			surrenderWithException(p);
			return;
		default:
			break;
		}
		game.setInitialChoice(p, kind);
	}

	@Override
	public void setUpdatedKindAfterDraw(Player p, FigureKind kind) throws RemoteException {
		//wrong player -> manipulated!
		if (!p.equals(player)) {
			surrenderWithException(player);
			return;
		}
		
		//choice is no valid figure kind -> manipulated!
		switch (kind) {
		case FLAG:
			surrenderWithException(p);
			return;
		case HIDDEN:
			surrenderWithException(p);
			return;
		case TRAP:
			surrenderWithException(p);
			return;
		default:
			break;
		}
		game.setUpdatedKindAfterDraw(p, kind);
	}

	@Override
	public void surrender(Player p) throws RemoteException {
		game.surrender(p);
	}
	
	private void surrenderWithException(Player p) throws RemoteException {
		game.surrender(p);
		throw new IllegalArgumentException();
	}

	@Override
	public Player getOpponent(Player p) throws RemoteException {
		return game.getOpponent(p);
	}
}